﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace AMOOF {
    internal delegate void DelegateLoadData(Dictionary<double, int> data);
    internal delegate void DelegateLoadStatistics(Statistics dataStatistics);
    internal delegate void DelegateSetProgress(int i);
    internal delegate void DelegateAppendProgress(int i);
    internal delegate void DelegateSetStatus(string s);
    internal delegate void DelegateLoadHistogram(Histogram histo);
    internal delegate void DelegateLoadReports(Dictionary<string, Report> reports);
    internal delegate void DelegateLoadSolver(Solver solver);
    internal delegate void DelegateEnableTab(int tabNumber);

    public partial class FormAMOOF : Form {

        private bool debugMode = false;

        public static FormAMOOF Instance;

        private DelegateLoadData m_delegateLoadData;
        private DelegateLoadStatistics m_delegateLoadStatistics;
        private DelegateSetProgress m_delegateSetProgress;
        private DelegateAppendProgress m_delegateAppendProgress;
        private DelegateSetStatus m_delegateSetStatus;
        private DelegateLoadHistogram m_delegateLoadHistogram;
        private DelegateLoadReports m_delegateLoadReports;
        private DelegateLoadSolver m_delegateLoadSolver;
        private DelegateEnableTab m_delegateEnableTab;

        private Dictionary<double, int> Data;
        private Statistics DataStatistics;
        private Histogram Histo;
        private Dictionary<string, Report> Reports;
        private Solver Solver;

        private const int navCount = 6;
        private NavPanel[] Navigation = new NavPanel[navCount];
        private string[] NavNames = { "Access Data",
                                      "Model Selection",
                                      "Optimize Models",
                                      "Optimize Results",
                                      "Fit Graphs",
                                      "User Help"
                                  };
        
        public FormAMOOF() {
            InitializeComponent();

            this.MinimumSize = new Size(1000, 800);
            this.MaximumSize = new Size(1000, 800);

            


            setNavigation();

            m_delegateLoadData = new DelegateLoadData(this.LoadData);
            m_delegateSetProgress = new DelegateSetProgress(this.SetProgress);
            m_delegateSetStatus = new DelegateSetStatus(this.SetStatus);
            m_delegateAppendProgress = new DelegateAppendProgress(this.AppendProgress);
            m_delegateLoadHistogram = new DelegateLoadHistogram(this.LoadHistogram);
            m_delegateLoadReports = new DelegateLoadReports(this.LoadReports);
            m_delegateLoadSolver = new DelegateLoadSolver(this.LoadSolver);
            m_delegateEnableTab = new DelegateEnableTab(this.EnableTab);

            Instance = this;
        }

        public void LoadSolver(Solver solver) {
            if (this.InvokeRequired) {
                m_delegateLoadSolver = new DelegateLoadSolver(this.LoadSolver);
                this.Invoke(m_delegateLoadSolver, new object[] { solver });
            }
            else {
                Solver = solver;
            }

            Navigation[2].Enabled = true;
        }

        public void LoadReports(Dictionary<string, Report> reports) {
            if (this.InvokeRequired) {
                m_delegateLoadReports = new DelegateLoadReports(this.LoadReports);
                this.Invoke(m_delegateLoadReports, new object[] { reports });
            }
            else {
                try {
                    Reports = reports;
                }
                catch (Exception e) {
                    Program.log(e.Message + "\r\n" + e.StackTrace);
                }
            }
            foreach (var kvp in reports) {
                if (!kvp.Value.Solved) {
                    Navigation[3].Enabled = false;
                    break;
                }
                Navigation[3].Enabled = true;
            }
            
        }

        public void EnableTab(int tabNumber) {
            if (this.InvokeRequired) {
                m_delegateEnableTab = new DelegateEnableTab(this.EnableTab);
                this.Invoke(m_delegateEnableTab, new object[] { tabNumber });
            }
            else {
                Navigation[tabNumber].Enabled = true;
            }
        }

        public void AppendProgress(int i) {
            if (this.InvokeRequired) {
                m_delegateAppendProgress = new DelegateAppendProgress(this.AppendProgress);
                this.Invoke(m_delegateAppendProgress, new object[] { i });
            }
            else {
                 if (!progressBarAMOOF.Visible) {
                    progressBarAMOOF.Visible = true;
                }

                i = this.progressBarAMOOF.Value + i >= 100 ? 0 : i;

                this.progressBarAMOOF.Value += i;

                this.statusStripAMOOF.Invalidate();
                //this.statusStripAMOOF.Update();
                this.statusStripAMOOF.Refresh();
            }
        }

        public void SetStatus(string s) {
            if (this.InvokeRequired) {
                m_delegateSetStatus = new DelegateSetStatus(this.SetStatus);
                this.Invoke(m_delegateSetStatus, new object[] { s });
            }
            else {
                this.lblStatus.Text = s;
                this.statusStripAMOOF.Invalidate();
                //this.statusStripAMOOF.Update();
                this.statusStripAMOOF.Refresh();
            }
            
        }

        public void SetProgress(int i) {
            if (this.InvokeRequired) {
                m_delegateAppendProgress = new DelegateAppendProgress(SetProgress);
                this.Invoke(m_delegateAppendProgress, new object[] { i });
            }
            else {
                if (!progressBarAMOOF.Visible) {
                    progressBarAMOOF.Visible = true;
                }

                if (i >= 0) {

                    i = i > 100 ? 100 : i;
                    this.progressBarAMOOF.Value = i;
                }
                else {
                    progressBarAMOOF.Visible = false;
                }

                this.statusStripAMOOF.Invalidate();
                this.statusStripAMOOF.Update();
            }
        }

        /// <summary>
        /// Sets the private variable "Data" to the passed in paramenter.
        /// This is used with a delegate from a different thread.
        /// </summary>
        /// <param name="data">The data set</param>
        public void LoadData(Dictionary<double, int> data) {
            if (this.InvokeRequired) {
                m_delegateLoadData = new DelegateLoadData(LoadData);
                this.Invoke(m_delegateLoadData, new object[] { data });
            }
            else {
                this.Data = data;
                //TODO:
                //Add loop to apply user-defined options here
                //add the histogram

                progressBarAMOOF.Visible = false;

                this.SetStatus("Data Import Complete! Please review the imported data and go to the Model Selection Tab.");

                this.statusStripAMOOF.Invalidate();
                this.statusStripAMOOF.Refresh();

                Navigation[1].Enabled = true;

            }
        }

        public void LoadStatistics(Statistics dataStatistics) {
            if (this.InvokeRequired) {
                m_delegateLoadStatistics = new DelegateLoadStatistics(LoadStatistics);
                this.Invoke(m_delegateLoadStatistics, new object[] { dataStatistics });
            }
            else {
                this.DataStatistics = dataStatistics;
            }
        }

        public void LoadHistogram(Histogram histo) {
            if (this.InvokeRequired) {
                m_delegateLoadHistogram = new DelegateLoadHistogram(LoadHistogram);
                this.Invoke(m_delegateLoadHistogram, new object[] { histo });
            }
            else {
                this.Histo = histo;
            }
        }

        //So child members can get to this stuff
        //**********************************//
        public Histogram GetHistogram() {
            return this.Histo;
        }

        public Statistics GetStatistics() {
            return this.DataStatistics;
        }

        public Dictionary<double, int> GetData() {
            return this.Data;
        }

        public Dictionary<string, Report> GetReports() {
            return this.Reports;
        }

        public Solver GetSolver() {
            return this.Solver;
        }

        public Report GetReport(string reportName) {
            return Reports[reportName];
        }
        //*********************************//


        private void setNavigation() {

            int offset = 52;
            int width = pnlNavigation.Width - (offset / 2);
            int height = pnlNavigation.Height;
            

            while (width % navCount != 0) {
                width--;
                offset++;
            }

            width = width / navCount;
            offset = offset / 2;

            Font f = new Font("Arial", 12, FontStyle.Regular);

            for (int i = 0; i < navCount; i++) {
                

                NavPanel p = new NavPanel();
                p.Text = NavNames[i];
                p.Name = NavNames[i].Replace(" ", String.Empty);
                p.Control = Reflector.GetClass<UserControl>("AMOOF." + p.Name);
                p.Control.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top;
                p.Font = f;
                //p.Controls.Add(l);

                p.Location = new Point((width * i) + (offset / 2), 0);
                p.Size = new Size(width, height);
                p.BackgroundImageLayout = ImageLayout.Stretch;
                p.MouseEnter += new EventHandler(navPanel_MouseEnter);
                p.MouseLeave += new EventHandler(navPanel_MouseLeave);
                p.MouseClick += new MouseEventHandler(navPanel_MouseClick);
                p.Visible = true;
                p.Index = i;

                Navigation[i] = p;
                pnlNavigation.Controls.Add(p);
                
            }

            Navigation[0].Active = true;
            Navigation[0].BackgroundImage = Reflector.GetResource<Bitmap>("active_left");
            Navigation[0].Font = new Font("Arial", 12, FontStyle.Bold);
            Navigation[5].BackgroundImage = Reflector.GetResource<Bitmap>("inactive_right");
            Navigation[5].Enabled = true;

            for (int i = 1; i < (navCount - 1); i++) {
                Navigation[i].BackgroundImage = Reflector.GetResource<Bitmap>("inactive_center");
                Navigation[i].Enabled = debugMode;
            }


        }

        private void navPanel_MouseEnter(object sender, EventArgs e) {
            if (((NavPanel)sender).Index == 0) {
                ((NavPanel)sender).BackgroundImage = Reflector.GetResource<Bitmap>("hover_left");
            }
            else if (((NavPanel)sender).Index == (navCount - 1)) {
                ((NavPanel)sender).BackgroundImage = Reflector.GetResource<Bitmap>("hover_right");
            }
            else {
                ((NavPanel)sender).BackgroundImage = Reflector.GetResource<Bitmap>("hover_center");
            }
        }

        private void navPanel_MouseLeave(object sender, EventArgs e) {
            string activeState = ((NavPanel)sender).Active ? "active" : "inactive";
            if (((NavPanel)sender).Index == 0) {
                ((NavPanel)sender).BackgroundImage = Reflector.GetResource<Bitmap>(activeState + "_left");
            }
            else if (((NavPanel)sender).Index == (navCount - 1)) {
                ((NavPanel)sender).BackgroundImage = Reflector.GetResource<Bitmap>(activeState + "_right");
            }
            else {
                ((NavPanel)sender).BackgroundImage = Reflector.GetResource<Bitmap>(activeState + "_center");
            }
        }

        private void navPanel_MouseClick(object sender, EventArgs e) {
            //This works to display the progress Bar
            //progressBarAMOOF.Visible = true;
            //this.Invalidate();
            
            if (!((NavPanel)sender).Active) {
                pnlContainer.Controls.Clear();

                foreach (NavPanel p in Navigation) {
                    p.Active = false;
                    string activeState = "inactive";
                    p.Font = new Font("Arial", 12, FontStyle.Regular);
                    
                    if (((NavPanel)sender).Equals(p)) {
                        pnlContainer.Controls.Add(p.Control);
                        activeState = "active";
                        p.Active = true;
                        p.Font = new Font("Arial", 12, FontStyle.Bold);
                    }

                    if(p.Index == 0) {
                        p.BackgroundImage = Reflector.GetResource<Bitmap>(activeState + "_left");
                    }
                    else if (p.Index == (navCount - 1)) {
                        p.BackgroundImage = Reflector.GetResource<Bitmap>(activeState + "_right");
                    }
                    else {
                        p.BackgroundImage = Reflector.GetResource<Bitmap>(activeState + "_center");
                    }
                }
            }
        }

        private void FormAMOOF_Load(object sender, EventArgs e) {
            pnlContainer.Controls.Add(Navigation[0].Control);
        }


    }
}
